#include "Widget.h"

#include "Compositor.h"
#include "Defines.h"
#include "App.h"

namespace Y{

Compositor * Widget::compositor = NULL;

std::map < OString, long > Widget::drawingFlagMap = std::map<OString,long>();

Widget::Widget ():
	Entity(NULL),
	texture(NULL),
	color(1,1,1,1),
	dimensions(1,1)
{
	static bool first = true;
	if ( first ) { _WidgetInit(); }
	App->firstRites(this);
}

Widget::Widget (Widget *w):
	Entity(w),
	texture(NULL),
	color(1,1,1,1),
	dimensions(1,1)
{
	static bool first = true;
	if ( first ) { _WidgetInit(); }
	App->firstRites(this);
}

Widget::~Widget(){
	App->lastRites(this);
}

void Widget::handleConfig ( ConfigVector& cv ){

	for ( int i = 0; i < cv.size(); ++i ){
		if ( cv[i].name.lenientEquals("texture") ){
			texture = cv[i].to<Texture*>();
			handled();
		}
		else if ( cv[i].name.lenientEquals("color") ){
			color = cv[i].to<Vertex4f>();
			handled();
		}
		else if ( cv[i].name.lenientEquals("position") ){
			position = cv[i].to<Vertex3f>();
			handled();
		}
		else if ( cv[i].name.lenientEquals("dimensions") ){
			dimensions = cv[i].to<Vertex2f>();
			handled();
			
		}
		else{
			for ( iteratorLoop2(drawingFlagMap,it) ){
				if ( cv[i].name.lenientEquals(it->first) ){
					setDrawingFlag(it->second,cv[i].to<bool>());
					handled();
					break;
				}
			}
		}
	}
}

void Widget::setDrawingFlag	(int f,bool b){ drawingFlags.setFlagTo(f,b); }
bool Widget::hasDrawingFlag	(int f){ return drawingFlags.includes(f); }

void Widget::drawingSubsystem (Compositor *c){
//	compositor = c;
	
	if ( ! hasDrawingFlag(NO_BACKGROUND) ){
		drawBackground();
	}
}

void Widget::preDraw (Compositor *c) {
	compositor = c;
	compositor->state.position() += this->position;
	compositor->state.color() *= this->color;
	compositor->state.pushPosition();
	compositor->state.pushColor();
}

void Widget::drawBackground	(){
	compositor->state.texture() = texture;
	drawQuad(0,0,dimensions.x(),dimensions.y());
}

void Widget::postDraw () {
	compositor->state.popPosition();
	compositor->state.popColor();
}

ClippingPoly Widget::getClippingPoly (){
	ClippingPoly p(
		position + compositor->state.position(),
		Vertex3f(position.x() + dimensions.x(),position.y()) + compositor->state.position(),
		Vertex3f(position.x() + dimensions.x(),position.y() + dimensions.y()) + compositor->state.position(),
		Vertex3f(position.x(),position.y() + dimensions.y()) + compositor->state.position()
	);
	return p;
}

bool Widget::mousePress		(float x, float y){return true;}
bool Widget::mouseRelease	(float x, float y){return true;}
bool Widget::mouseMove		(float x, float y){return true;}
bool Widget::mouseDrag		(float x, float y){return true;}
bool Widget::mouseEnter		(){return true;}
bool Widget::mouseExit		(){return true;}
bool Widget::scrollWheel	(float dx,float dy,float dz){return true;}
bool Widget::keyPress		(unsigned char c, int mod){return true;}
bool Widget::keyRelease		(unsigned char c, int mod){return true;}
	void Widget::eventSubsystem		(int e){
		if ( ! acceptsEvent(e) ){ parent()->eventSubsystem(e); }
		bool r = false;
		if ( e == MOUSE_ENTER ){ r = mouseEnter(); }
		else if ( e == MOUSE_EXIT ){ r = mouseExit(); }
		if ( ! r ){ parent()->eventSubsystem(e); }
	}
	void Widget::eventSubsystem		(float x,float y,int e){
		if ( ! acceptsEvent(e) ){ parent()->eventSubsystem(x,y,e); }
		bool r = false;
		if ( e == MOUSE_PRESS ){ r = mousePress(x,y); }
		else if ( e == MOUSE_RELEASE ){ r = mouseRelease(x,y); }
		else if ( e == MOUSE_MOVE ){ r == mouseMove(x,y); }
		else if ( e == MOUSE_DRAG ){ r == mouseDrag(x,y); }
		if ( ! r ){ parent()->eventSubsystem(x,y,e); }
	}
	void Widget::eventSubsystem		(float x,float y,float z,int e){
		if ( ! acceptsEvent(e) ){ parent()->eventSubsystem(x,y,z,e); }
		bool r = false;
		if ( e == MOUSE_SCROLL ){ r = scrollWheel(x,y,z); }
		if ( ! r ){ parent()->eventSubsystem(x,y,z,e); }		
	}
	void Widget::eventSubsystem		(unsigned char c,int mod,int e){
		if ( ! acceptsEvent(e) ){ parent()->eventSubsystem(c,mod,e); }
		bool r = false;
		if ( e == KEY_PRESS ){ r = keyPress(c,mod); }
		else if ( e == KEY_RELEASE ){ r = keyRelease(c,mod); }
		if ( ! r ){ parent()->eventSubsystem(c,mod,e); }
	}
	
bool Widget::acceptsEvent	(int e){ return acceptedEvents.includes(e); }
void Widget::setAcceptsEvent(int e,bool b){ acceptedEvents.setFlagTo(e,b); }



void Widget::_WidgetInit (){
	drawingFlagMap["No Background"] = NO_BACKGROUND;
	drawingFlagMap["Parent Bounds Independent"] = PARENT_BOUNDS_INDEPENDENT;
	drawingFlagMap["Bounds Independent"] = BOUNDS_INDEPENDENT;
}



/*====================================================================================================================+
+=====================================================================================================================+
													Widget Drawing Function
======================================================================================================================+
+====================================================================================================================*/



void Widget::pushMatrix(){
	compositor->state.pushPosition();
}
void Widget::popMatrix(){
	compositor->state.popPosition();
}
void Widget::translate (float x,float y,float z){
	compositor->state.position().x() += x;
	compositor->state.position().y() += y;
	compositor->state.position().z() += z;
}

void Widget::pushColor (){
	compositor->state.pushColor();
}
void Widget::popColor (){
	compositor->state.popColor();
}
void Widget::multColor (const Vertex4f& c){
	compositor->state.color() *= c;
}
void Widget::setColor  (const Vertex4f& c){
	compositor->state.color() = c;
}

void Widget::setTexture (Texture *t){
	compositor->state.texture() = t;
}
//Primitive changing primitives
void Widget::drawQuad (float x,float y,float w,float h){
	ComPoly& p = compositor->geometry.startNewPoly( compositor->state.texture() );
	p.push_back( glVertex_tcnv( Vertex2f(0,1),compositor->state.color(),Vertex3f(0,0,1),Vertex3f(x,y,0) + compositor->state.position() ) );
	p.push_back( glVertex_tcnv( Vertex2f(1,1),compositor->state.color(),Vertex3f(0,0,1),Vertex3f(x + w,y,0) + compositor->state.position() ) );
	p.push_back( glVertex_tcnv( Vertex2f(1,0),compositor->state.color(),Vertex3f(0,0,1),Vertex3f(x + w,y + h,0) + compositor->state.position() ) );
	p.push_back( glVertex_tcnv( Vertex2f(0,0),compositor->state.color(),Vertex3f(0,0,1),Vertex3f(x,y + h,0) + compositor->state.position() ) );
}

void Widget::drawPoly (Vertex2f v[], int n){
	std::cout << "\n" << "draw poly as of yet unfinished";
}

}